#include <iostream>
#include <fstream>

#include "LOLCode.h"
#include "NodeAST.h"
#include "MyException.h"
#include "MyString.h"

LOLCode::LOLCode() : _bnf(NULL), _fileCPP(NULL), _fileLOL(NULL), _node(NULL)
{}

void			LOLCode::createAST(std::string const & file, bool newBNF)
{
  std::string		s;
  std::string		snew;

  this->parseVariable(file);
  this->_fileLOL = new FileLOLCode(file);
  if (newBNF == true)
    this->_bnf = new StaticNextBNF(this->_var);
  else
    this->_bnf = new StaticBNF(this->_var);
  s = this->_fileLOL->getLine();
  if (s != "")
    {
      if ((snew = this->_bnf->translate(s)) == "")
	throw new MyException (BNFERROR + s);
      this->_node = new NodeAST(*this, snew, 0);
      this->_node->nextAST();
    }
}

void			LOLCode::astToFile(std::string const & file)
{
  this->_fileCPP = new FileCPP(file);

  if (this->_node != NULL)
    {
      this->_fileCPP->writeLine(this->_node->getData());
      if (this->_node->getLeft() != NULL)
	this->_node->getLeft()->nextAstToFile();
      if (this->_node->getRight() != NULL)
	this->_node->getRight()->nextAstToFile();
    }
}

FileLOLCode &		LOLCode::getFileLOL() const
{
  return (*(this->_fileLOL));
}

FileCPP &		LOLCode::getFileCPP() const
{
  return (*(this->_fileCPP));
}

IBNF&			LOLCode::getBnf() const
{
  return (*(this->_bnf));
}

void			LOLCode::parseVariable(std::string const & file)
{
  std::ifstream		ifs;
  std::string		l;

  ifs.open(file.data());
  if (!ifs.is_open())
    throw new MyException (INPUT_FILE + file);
  while (!ifs.eof())
    {
      getline(ifs, l);
      if (!l.find("I HAS A "))
	this->parseVariableAdd(l.substr(8));
      else if (!l.find("LOL "))
	this->parseVariableAsign(l.substr(4));
    }
  std::map<std::string, std::string>::iterator	itb = this->_var.begin();
  std::map<std::string, std::string>::iterator	ite = this->_var.end();
  for (; itb != ite; ++itb)
    if (itb->second == "")
      throw new MyException (NOT_INITIALISED + itb->first);  
  ifs.close();
}

void			LOLCode::parseVariableAdd(std::string add)
{
  std::map<std::string, std::string>::iterator	itb = this->_var.begin();
  std::map<std::string, std::string>::iterator	ite = this->_var.end();

  MyString::trim(add);
  for (; itb != ite; ++itb)
    if (itb->first == add)
      throw new MyException (DOUBLE_DECLARATION + add);
  this->_var[add] = "";
}

void			LOLCode::parseVariableAsign(std::string asign)
{
  MyString::trim(asign);
  std::string		value = asign.substr(asign.find_last_of(" "));
  MyString::trim(value);
  asign = asign.substr(0, asign.find(" "));
  MyString::trim(asign);
  std::map<std::string, std::string>::iterator	itb = this->_var.find(asign);
  std::map<std::string, std::string>::iterator	ite = this->_var.end();

  if (itb == ite)
    throw new MyException (NOT_DECLARATION + asign);
  if (MyString::isNumber(value) == true)
    this->_var[itb->first] = "int ";
  else
    this->_var[itb->first] = "std::string ";
}
